home *** CD-ROM | disk | FTP | other *** search
Wrap
# Source Generated with Decompyle++ # File: in.pyc (Python 2.6) import warnings warnings.filterwarnings('ignore', 'apt API not stable yet', FutureWarning) import apt import apt_pkg import os import os.path as os import re import logging import string import statvfs import time import gettext import datetime import threading import ConfigParser from subprocess import Popen, PIPE from DistUpgradeGettext import gettext as _ from DistUpgradeGettext import ngettext from DistUpgradeConfigParser import DistUpgradeConfig from DistUpgradeView import FuzzyTimeToStr class CacheException(Exception): pass class CacheExceptionLockingFailed(CacheException): pass class CacheExceptionDpkgInterrupted(CacheException): pass KERNEL_INITRD_SIZE = 15 * 1024 * 1024 class FreeSpaceRequired(object): ''' FreeSpaceRequired object: This exposes: - the total size required (size_total) - the dir that requires the space (dir) - the additional space that is needed (size_needed) ''' def __init__(self, size_total, dir, size_needed): self.size_total = size_total self.dir = dir self.size_needed = size_needed def __str__(self): return 'FreeSpaceRequired Object: Dir: %s size_total: %s size_needed: %s' % (self.dir, self.size_total, self.size_needed) class NotEnoughFreeSpaceError(CacheException): ''' Exception if there is not enough free space for this operation ''' def __init__(self, free_space_required_list): self.free_space_required_list = free_space_required_list class MyCache(apt.Cache): ReInstReq = 1 HoldReInstReq = 3 def __init__(self, config, view, quirks, progress = None, lock = True): apt.Cache.__init__(self, progress) self.to_install = [] self.to_remove = [] self.view = view self.quirks = quirks self.lock = False self.partialUpgrade = False self.config = config self.metapkgs = self.config.getlist('Distro', 'MetaPkgs') self._listsLock = -1 if lock: try: apt_pkg.PkgSystemLock() self.lockListsDir() self.lock = True except SystemError: e = None if 'dpkg --configure -a' in str(e): raise CacheExceptionDpkgInterrupted, e 'dpkg --configure -a' in str(e) raise CacheExceptionLockingFailed, e except: None<EXCEPTION MATCH>SystemError None<EXCEPTION MATCH>SystemError self.removal_blacklist = config.getListFromFile('Distro', 'RemovalBlacklistFile') self.uname = Popen([ 'uname', '-r'], stdout = PIPE).communicate()[0].strip() self._initAptLog() if config.get('Sources', 'From') == 'hardy' and 'RELEASE_UPGRADE_NO_RECOMMENDS' not in os.environ: apt_pkg.Config.Set('APT::Install-Recommends', 'true') def reqReinstallPkgs(self): ''' return the packages not downloadable packages in reqreinst state ''' reqreinst = set() for pkg in self: if not (pkg.candidateDownloadable): if pkg._pkg.InstState == self.ReInstReq or pkg._pkg.InstState == self.HoldReInstReq: reqreinst.add(pkg.name) continue return reqreinst reqReinstallPkgs = property(reqReinstallPkgs) def fixReqReinst(self, view): ''' check for reqreinst state and offer to fix it ''' reqreinst = self.reqReinstallPkgs if len(reqreinst) > 0: header = ngettext('Remove package in bad state', 'Remove packages in bad state', len(reqreinst)) summary = ngettext("The package '%s' is in an inconsistent state and needs to be reinstalled, but no archive can be found for it. Do you want to remove this package now to continue?", "The packages '%s' are in an inconsistent state and need to be reinstalled, but no archives can be found for them. Do you want to remove these packages now to continue?", len(reqreinst)) % ', '.join(reqreinst) if view.askYesNoQuestion(header, summary): self.releaseLock() cmd = [ 'dpkg', '--remove', '--force-remove-reinstreq'] + list(reqreinst) view.getTerminal().call(cmd) self.getLock() return True return False def _initAptLog(self): ''' init logging, create log file''' logdir = self.config.getWithDefault('Files', 'LogDir', '/var/log/dist-upgrade') apt_pkg.Config.Set('Dir::Log', logdir) apt_pkg.Config.Set('Dir::Log::Terminal', 'apt-term.log') self.logfd = os.open(os.path.join(logdir, 'apt.log'), os.O_RDWR | os.O_CREAT | os.O_APPEND | os.O_SYNC, 420) os.write(self.logfd, 'Log time: %s\n' % datetime.datetime.now()) apt_pkg.Config.Set('Debug::pkgProblemResolver', 'true') apt_pkg.Config.Set('Debug::pkgDepCache::AutoInstall', 'true') def _startAptResolverLog(self): if hasattr(self, 'old_stdout'): os.close(self.old_stdout) os.close(self.old_stderr) self.old_stdout = os.dup(1) self.old_stderr = os.dup(2) os.dup2(self.logfd, 1) os.dup2(self.logfd, 2) def _stopAptResolverLog(self): os.fsync(1) os.fsync(2) os.dup2(self.old_stdout, 1) os.dup2(self.old_stderr, 2) def withResolverLog(f): ''' decorator to ensure that the apt output is logged ''' def wrapper(*args, **kwargs): args[0]._startAptResolverLog() res = f(*args, **kwargs) args[0]._stopAptResolverLog() return res return wrapper def requiredDownload(self): ''' get the size of the packages that are required to download ''' pm = apt_pkg.GetPackageManager(self._depcache) fetcher = apt_pkg.GetAcquire() pm.GetArchives(fetcher, self._list, self._records) return fetcher.FetchNeeded requiredDownload = property(requiredDownload) def additionalRequiredSpace(self): ''' get the size of the additional required space on the fs ''' return self._depcache.UsrSize additionalRequiredSpace = property(additionalRequiredSpace) def isBroken(self): ''' is the cache broken ''' return self._depcache.BrokenCount > 0 isBroken = property(isBroken) def lockListsDir(self): name = apt_pkg.Config.FindDir('Dir::State::Lists') + 'lock' self._listsLock = apt_pkg.GetLock(name) if self._listsLock < 0: e = "Can not lock '%s' " % name raise CacheExceptionLockingFailed, e self._listsLock < 0 def unlockListsDir(self): if self._listsLock > 0: os.close(self._listsLock) self._listsLock = -1 def update(self, fprogress = None): ''' our own update implementation is required because we keep the lists dir lock ''' self.unlockListsDir() res = apt.Cache.update(self, fprogress) self.lockListsDir() if res == False: raise IOError('apt.cache.update() returned False, but did not raise exception?!?') res == False def commit(self, fprogress, iprogress): logging.info('cache.commit()') if self.lock: self.releaseLock() apt.Cache.commit(self, fprogress, iprogress) def releaseLock(self, pkgSystemOnly = True): if self.lock: try: apt_pkg.PkgSystemUnLock() self.lock = False except SystemError: e = None logging.debug('failed to SystemUnLock() (%s) ' % e) except: None<EXCEPTION MATCH>SystemError None<EXCEPTION MATCH>SystemError def getLock(self, pkgSystemOnly = True): if not self.lock: try: apt_pkg.PkgSystemLock() self.lock = True except SystemError: e = None logging.debug('failed to SystemLock() (%s) ' % e) except: None<EXCEPTION MATCH>SystemError None<EXCEPTION MATCH>SystemError def downloadable(self, pkg, useCandidate = True): ''' check if the given pkg can be downloaded ''' if useCandidate: ver = self._depcache.GetCandidateVer(pkg._pkg) else: ver = pkg._pkg.CurrentVer if ver == None: logging.warning("no version information for '%s' (useCandidate=%s)" % (pkg.name, useCandidate)) return False return ver.Downloadable def fixBroken(self): """ try to fix broken dependencies on the system, may throw SystemError when it can't""" return self._depcache.FixBroken() def create_snapshot(self): ''' create a snapshot of the current changes ''' self.to_install = [] self.to_remove = [] for pkg in self.getChanges(): if pkg.markedInstall or pkg.markedUpgrade: self.to_install.append(pkg.name) if pkg.markedDelete: self.to_remove.append(pkg.name) continue def clear(self): self._depcache.Init() def restore_snapshot(self): ''' restore a snapshot ''' actiongroup = apt_pkg.GetPkgActionGroup(self._depcache) self.clear() for name in self.to_remove: pkg = self[name] pkg.markDelete() for name in self.to_install: pkg = self[name] pkg.markInstall(autoFix = False, autoInst = False) def needServerMode(self): ''' This checks if we run on a desktop or a server install. A server install has more freedoms, for a desktop install we force a desktop meta package to be install on the upgrade. We look for a installed desktop meta pkg and for key dependencies, if none of those are installed we assume server mode ''' metapkgs = self.config.getlist('Distro', 'MetaPkgs') for key in metapkgs: if self.has_key(key) and self[key].isInstalled: logging.debug("needServerMode(): run in 'desktop' mode, (because of pkg '%s')" % key) return False deps_found = True for pkg in self.config.getlist(key, 'KeyDependencies'): if self.has_key(pkg): pass deps_found &= self[pkg].isInstalled if deps_found: logging.debug("needServerMode(): run in 'desktop' mode, (because of key deps for '%s')" % key) return False logging.debug('needServerMode(): can not find a desktop meta package or key deps, running in server mode') return True def sanityCheck(self, view): ''' check if the cache is ok and if the required metapkgs are installed ''' if self.isBroken: try: logging.debug('Have broken pkgs, trying to fix them') self.fixBroken() except SystemError: view.error(_('Broken packages'), _("Your system contains broken packages that couldn't be fixed with this software. Please fix them first using synaptic or apt-get before proceeding.")) return False None<EXCEPTION MATCH>SystemError return True def markInstall(self, pkg, reason = ''): logging.debug("Installing '%s' (%s)" % (pkg, reason)) if self.has_key(pkg): self[pkg].markInstall() if not self[pkg].markedInstall or self[pkg].markedUpgrade: logging.error("Installing/upgrading '%s' failed" % pkg) def markUpgrade(self, pkg, reason = ''): logging.debug("Upgrading '%s' (%s)" % (pkg, reason)) if self.has_key(pkg) and self[pkg].isInstalled: self[pkg].markUpgrade() if not self[pkg].markedUpgrade: logging.error("Upgrading '%s' failed" % pkg) def markRemove(self, pkg, reason = ''): logging.debug("Removing '%s' (%s)" % (pkg, reason)) if self.has_key(pkg): self[pkg].markDelete() def markPurge(self, pkg, reason = ''): logging.debug("Purging '%s' (%s)" % (pkg, reason)) if self.has_key(pkg): self._depcache.MarkDelete(self[pkg]._pkg, True) def keepInstalledRule(self): ''' run after the dist-upgrade to ensure that certain packages are kept installed ''' def keepInstalled(self, pkgname, reason): if self.has_key(pkgname) and self[pkgname].isInstalled and self[pkgname].markedDelete: self.markInstall(pkgname, reason) for pkgname in self.config.getlist('Distro', 'KeepInstalledPkgs'): keepInstalled(self, pkgname, 'Distro KeepInstalledPkgs rule') for key in self.metapkgs: if self.has_key(key): if self[key].isInstalled or self[key].markedInstall: for pkgname in self.config.getlist(key, 'KeepInstalledPkgs'): keepInstalled(self, pkgname, '%s KeepInstalledPkgs rule' % key) if self.config.get('Options', 'withNetwork') == 'True': logging.debug('Running KeepInstalledSection rules') for section in self.config.getlist('Distro', 'KeepInstalledSection'): for pkg in self: if pkg.markedDelete and pkg.section == section: keepInstalled(self, pkg.name, 'Distro KeepInstalledSection rule: %s' % section) continue for key in self.metapkgs: if self.has_key(key): if self[key].isInstalled or self[key].markedInstall: for section in self.config.getlist(key, 'KeepInstalledSection'): for pkg in self: if pkg.markedDelete and pkg.section == section: keepInstalled(self, pkg.name, '%s KeepInstalledSection rule: %s' % (key, section)) continue def postUpgradeRule(self): ''' run after the upgrade was done in the cache ''' for rule, action in [ ('Install', self.markInstall), ('Upgrade', self.markUpgrade), ('Remove', self.markRemove), ('Purge', self.markPurge)]: for pkg in self.config.getlist('Distro', 'PostUpgrade%s' % rule): action(pkg, 'Distro PostUpgrade%s rule' % rule) for key in self.metapkgs: if self.has_key(key): if self[key].isInstalled or self[key].markedInstall: for pkg in self.config.getlist(key, 'PostUpgrade%s' % rule): action(pkg, '%s PostUpgrade%s rule' % (key, rule)) if not self.partialUpgrade: self.quirks.run('PostDistUpgradeCache') def identifyObsoleteKernels(self): logging.debug('identifyObsoleteKernels()') obsolete_kernels = set() version = self.config.get('KernelRemoval', 'Version') basenames = self.config.getlist('KernelRemoval', 'BaseNames') types = self.config.getlist('KernelRemoval', 'Types') for pkg in self: for base in basenames: basename = '%s-%s-' % (base, version) for type in types: if pkg.name.startswith(basename) and pkg.name.endswith(type) and pkg.isInstalled: if pkg.name == '%s-%s' % (base, self.uname): logging.debug('skipping running kernel %s' % pkg.name) continue logging.debug("removing obsolete kernel '%s'" % pkg.name) obsolete_kernels.add(pkg.name) continue logging.debug("identifyObsoleteKernels found '%s'" % obsolete_kernels) return obsolete_kernels def checkForNvidia(self): ''' this checks for nvidia hardware and checks what driver is needed ''' logging.debug('nvidiaUpdate()') try: NvidiaDetection = NvidiaDetection import NvidiaDetector.nvidiadetector except ImportError: e = None logging.error('NvidiaDetector can not be imported %s' % e) return False try: nv = NvidiaDetection(datadir = './modaliases/') for oldDriver in nv.oldPackages: if self.has_key(oldDriver) and self[oldDriver].isInstalled: self.markRemove(oldDriver, 'old nvidia driver') break continue else: return False driver = None.selectDriver() logging.debug("nv.selectDriver() returned '%s'" % driver) if self.has_key(driver): if not self[driver].markedInstall: pass if not (self[driver].markedUpgrade): self[driver].markInstall() logging.info('installing %s as suggested by NvidiaDetector' % driver) return True except Exception: e = None logging.error('NvidiaDetection returned a error: %s' % e) return False def checkForKernel(self): ''' check for the running kernel and try to ensure that we have an updated version ''' logging.debug("Kernel uname: '%s' " % self.uname) try: (version, build, flavour) = self.uname.split('-') except Exception: e = None logging.warning("Can't parse kernel uname: '%s' (self compiled?)" % e) return False dmesg = Popen([ 'dmesg'], stdout = PIPE).communicate()[0] if 'WARNING: NR_CPUS limit' in dmesg: logging.debug('UP kernel on SMP system!?!') flavour = 'generic' kernel = 'linux-image-%s' % flavour if not self.has_key(kernel): logging.warning("No kernel: '%s'" % kernel) return False if not self[kernel].isInstalled or self[kernel].markedInstall: logging.debug("Selecting new kernel '%s'" % kernel) self[kernel].markInstall() return True def checkPriority(self): need = ('required',) removeEssentialOk = self.config.getlist('Distro', 'RemoveEssentialOk') for pkg in self: ver = pkg._pcache._depcache.GetCandidateVer(pkg._pkg) if ver and ver.Priority == 0: logging.error('Package %s has no priority set' % pkg.name) continue if pkg.candidateDownloadable: if not pkg.isInstalled: pass if not (pkg.markedInstall) and pkg.name not in removeEssentialOk and pkg.priority in need: self.markInstall(pkg.name, "priority in required set '%s' but not scheduled for install" % need) continue def updateGUI(self, view, lock): while lock.locked(): view.processEvents() time.sleep(0.01) def distUpgrade(self, view, serverMode, partialUpgrade): lock = threading.Lock() lock.acquire() t = threading.Thread(target = self.updateGUI, args = (self.view, lock)) t.start() try: self.upgrade(True) self.checkPriority() self.keepInstalledRule() self.checkForKernel() self.checkForNvidia() self.postUpgradeRule() if not serverMode: self._installMetaPkgs(view) self._verifyChanges() except SystemError: e = None lock.release() t.join() details = _('An unresolvable problem occurred while calculating the upgrade:\n%s\n\n This can be caused by:\n * Upgrading to a pre-release version of Ubuntu\n * Running the current pre-release version of Ubuntu\n * Unofficial software packages not provided by Ubuntu\n\n' % e) if partialUpgrade: details += _('This is most likely a transient problem, please try again later.') else: details += _("If none of this applies, then please report this bug against the 'update-manager' package and include the files in /var/log/dist-upgrade/ in the bug report.") self._stopAptResolverLog() view.error(_('Could not calculate the upgrade'), details) self._startAptResolverLog() logging.error("Dist-upgrade failed: '%s'", e) return False lock.release() t.join() untrusted = [] for pkg in self.getChanges(): if pkg.markedDelete: continue if pkg.markedDowngrade: for ver in pkg._pkg.VersionList: if apt_pkg.VersionCompare(ver.VerStr, pkg.installedVersion) < 0: for verFileIter, index in ver.FileList: indexfile = pkg._list.FindIndex(verFileIter) if indexfile and not (indexfile.IsTrusted): untrusted.append(pkg.name) break continue continue origins = pkg.candidateOrigin trusted = False for origin in origins: trusted |= origin.trusted if not trusted: untrusted.append(pkg.name) continue try: b = self.config.getboolean('Distro', 'AllowUnauthenticated') if b: logging.warning('AllowUnauthenticated set!') return True except ConfigParser.NoOptionError: e = None if len(untrusted) > 0: untrusted.sort() logging.error("Unauthenticated packages found: '%s'" % ' '.join(untrusted)) self._stopAptResolverLog() view.error(_('Error authenticating some packages'), _('It was not possible to authenticate some packages. This may be a transient network problem. You may want to try again later. See below for a list of unauthenticated packages.'), '\n'.join(untrusted)) self._startAptResolverLog() return False return True distUpgrade = withResolverLog(distUpgrade) def _verifyChanges(self): """ this function tests if the current changes don't violate our constrains (blacklisted removals etc) """ removeEssentialOk = self.config.getlist('Distro', 'RemoveEssentialOk') for pkg in self.getChanges(): if pkg.markedDelete and self._inRemovalBlacklist(pkg.name): logging.debug("The package '%s' is marked for removal but it's in the removal blacklist", pkg.name) raise SystemError, _("The package '%s' is marked for removal but it is in the removal blacklist.") % pkg.name self._inRemovalBlacklist(pkg.name) if pkg.markedDelete and pkg._pkg.Essential == True and pkg.name not in removeEssentialOk: logging.debug("The package '%s' is marked for removal but it's a ESSENTIAL package", pkg.name) raise SystemError, _("The essential package '%s' is marked for removal.") % pkg.name pkg.name not in removeEssentialOk badVersions = self.config.getlist('Distro', 'BadVersions') for bv in badVersions: (pkgname, ver) = bv.split('_') if self.has_key(pkgname) and self[pkgname].candidateVersion == ver: if self[pkgname].markedInstall or self[pkgname].markedUpgrade: raise SystemError, "Trying to install blacklisted version '%s'" % bv self[pkgname].markedUpgrade return True def installedTasks(self): tasks = { } installed_tasks = set() for pkg in self: if not pkg._lookupRecord(): logging.debug("no PkgRecord found for '%s', skipping " % pkg.name) continue for line in pkg._pcache._records.Record.split('\n'): if line.startswith('Task:'): for task in line[len('Task:'):].split(','): task = task.strip() if not tasks.has_key(task): tasks[task] = set() tasks[task].add(pkg.name) for task in tasks: installed = True for pkgname in tasks[task]: if not self[pkgname].isInstalled: installed = False break continue if installed: installed_tasks.add(task) continue return installed_tasks installedTasks = property(installedTasks) def installTasks(self, tasks): logging.debug('running installTasks') for pkg in self: if pkg.markedInstall or pkg.isInstalled: continue pkg._lookupRecord() if not hasattr(pkg._pcache._records, 'Record') and pkg._pcache._records.Record: logging.warning("can not find Record for '%s'" % pkg.name) continue for line in pkg._pcache._records.Record.split('\n'): if line.startswith('Task:'): for task in line[len('Task:'):].split(','): task = task.strip() if task in tasks: pkg.markInstall() continue return True def _installMetaPkgs(self, view): def metaPkgInstalled(): ''' internal helper that checks if at least one meta-pkg is installed or marked install ''' for key in metapkgs: if self.has_key(key): pkg = self[key] if pkg.isInstalled and pkg.markedDelete: logging.debug("metapkg '%s' installed but markedDelete" % pkg.name) if pkg.isInstalled or not (pkg.markedDelete) or self[key].markedInstall: return True continue self[key].markedInstall return False metapkgs = self.config.getlist('Distro', 'MetaPkgs') for pkg in self.config.getlist('Distro', 'BaseMetaPkgs'): self[pkg].markInstall() for key in metapkgs: try: if self.has_key(key) and self[key].isInstalled: logging.debug("Marking '%s' for upgrade" % key) self[key].markUpgrade() continue except SystemError: (None, None) e = (None, None) logging.debug("Can't mark '%s' for upgrade (%s)" % (key, e)) raise SystemError, _("Can not mark '%s' for upgrade") % key continue if not metaPkgInstalled(): view.error(_("Can't guess meta-package"), _('Your system does not contain a ubuntu-desktop, kubuntu-desktop, xubuntu-desktop or edubuntu-desktop package and it was not possible to detect which version of Ubuntu you are running.\n Please install one of the packages above first using synaptic or apt-get before proceeding.')) return False return True def _inRemovalBlacklist(self, pkgname): for expr in self.removal_blacklist: if re.compile(expr).match(pkgname): return True return False def tryMarkObsoleteForRemoval(self, pkgname, remove_candidates, foreign_pkgs): if pkgname.endswith(self.uname): logging.debug("skipping running kernel pkg '%s'" % pkgname) return False if self._inRemovalBlacklist(pkgname): logging.debug("skipping '%s' (in removalBlacklist)" % pkgname) return False for section in self.config.getlist('Distro', 'KeepInstalledSection'): if self.has_key(pkgname) and self[pkgname].section == section: logging.debug("skipping '%s' (in KeepInstalledSection)" % pkgname) return False if not self.has_key(pkgname): return True try: purge = self.config.getboolean('Distro', 'PurgeObsoletes') except ConfigParser.NoOptionError: self.has_key(pkgname) e = self.has_key(pkgname) self[pkgname].section == section purge = False except: self._inRemovalBlacklist(pkgname) actiongroup = apt_pkg.GetPkgActionGroup(self._depcache) self.create_snapshot() try: self[pkgname].markDelete(purge = purge) self.view.processEvents() for pkg in self.getChanges(): if pkg.name not in remove_candidates and pkg.name in foreign_pkgs or self._inRemovalBlacklist(pkg.name): logging.debug("package '%s' has unwanted removals, skipping" % pkgname) self.restore_snapshot() return False except (SystemError, KeyError): self._inRemovalBlacklist(pkgname) e = self._inRemovalBlacklist(pkgname) pkgname.endswith(self.uname) logging.warning("_tryMarkObsoleteForRemoval failed for '%s' (%s: %s)" % (pkgname, repr(e), e)) self.restore_snapshot() return False return True tryMarkObsoleteForRemoval = withResolverLog(tryMarkObsoleteForRemoval) def _getObsoletesPkgs(self): ''' get all package names that are not downloadable ''' obsolete_pkgs = set() for pkg in self: if pkg.isInstalled: if not self.anyVersionDownloadable(pkg): obsolete_pkgs.add(pkg.name) self.anyVersionDownloadable(pkg) return obsolete_pkgs def anyVersionDownloadable(self, pkg): ''' helper that checks if any of the version of pkg is downloadable ''' for ver in pkg._pkg.VersionList: if ver.Downloadable: return True return False def _getUnusedDependencies(self): ''' get all package names that are not downloadable ''' unused_dependencies = set() for pkg in self: if pkg.isInstalled and self._depcache.IsGarbage(pkg._pkg): unused_dependencies.add(pkg.name) continue return unused_dependencies def _getForeignPkgs(self, allowed_origin, fromDist, toDist): ''' get all packages that are installed from a foreign repo (and are actually downloadable) ''' foreign_pkgs = set() for pkg in self: if pkg.isInstalled and self.downloadable(pkg): foreign = True for origin in pkg.candidateOrigin: if fromDist in origin.archive and origin.origin == allowed_origin: foreign = False if toDist in origin.archive and origin.origin == allowed_origin: foreign = False continue if foreign: foreign_pkgs.add(pkg.name) foreign return foreign_pkgs def checkFreeSpace(self): ''' this checks if we have enough free space on /var, /boot and /usr with the given cache Note: this can not be fully accurate if there are multiple mountpoints for /usr, /var, /boot ''' class FreeSpace(object): ''' helper class that represents the free space on each mounted fs ''' def __init__(self, initialFree): self.free = initialFree self.need = 0 def make_fs_id(d): """ return 'id' of a directory so that directories on the same filesystem get the same id (simply the mount_point) """ for mount_point in mounted: if d.startswith(mount_point): return mount_point return '/' mounted = [] mnt_map = { } fs_free = { } for line in open('/proc/mounts'): try: (what, where, fs, options, a, b) = line.split() except ValueError: (None,) e = (None,) logging.debug("line '%s' in /proc/mounts not understood (%s)" % (line, e)) continue except: (None,) if where not in mounted: mounted.append(where) continue (None,) mounted.sort(cmp = (lambda a, b: cmp(len(a), len(b))), reverse = True) archivedir = apt_pkg.Config.FindDir('Dir::Cache::archives') aufs_rw_dir = '/tmp/' if hasattr(self, 'config') and self.config.getWithDefault('Aufs', 'Enabled', False): aufs_rw_dir = self.config.get('Aufs', 'RWDir') if not os.path.exists(aufs_rw_dir): os.makedirs(aufs_rw_dir) logging.debug('cache aufs_rw_dir: %s' % aufs_rw_dir) for d in [ '/', '/usr', '/var', '/boot', archivedir, aufs_rw_dir, '/home']: d = os.path.realpath(d) fs_id = make_fs_id(d) st = os.statvfs(d) free = st[statvfs.F_BAVAIL] * st[statvfs.F_FRSIZE] if fs_id in mnt_map: logging.debug('Dir %s mounted on %s' % (d, mnt_map[fs_id])) fs_free[d] = fs_free[mnt_map[fs_id]] continue logging.debug('Free space on %s: %s' % (d, free)) mnt_map[fs_id] = d fs_free[d] = FreeSpace(free) del mnt_map logging.debug("fs_free contains: '%s'" % fs_free) space_in_boot = 0 for pkg in self: if re.match('^linux-(image|image-debug)-[0-9.]*-.*', pkg.name): if pkg.markedInstall: logging.debug('%s (new-install) added with %s to boot space' % (pkg.name, KERNEL_INITRD_SIZE)) space_in_boot += KERNEL_INITRD_SIZE pkg.markedInstall required_for_aufs = 0 if hasattr(self, 'config') and self.config.getWithDefault('Aufs', 'Enabled', False): logging.debug('taking aufs overlay into space calculation') aufs_rw_dir = self.config.get('Aufs', 'RWDir') for pkg in self: if pkg.markedUpgrade or pkg.markedInstall: required_for_aufs += self._depcache.GetCandidateVer(pkg._pkg).Size continue for dir, size in [ (archivedir, self.requiredDownload), ('/usr', self.additionalRequiredSpace), ('/usr', 52428800), ('/boot', space_in_boot), ('/', 10485760), (aufs_rw_dir, required_for_aufs)]: dir = os.path.realpath(dir) logging.debug("dir '%s' needs '%s' of '%s' (%f)" % (dir, size, fs_free[dir], fs_free[dir].free)) fs_free[dir].free -= size fs_free[dir].need += size required_list = { } for dir in fs_free: if fs_free[dir].free < 0: free_at_least = apt_pkg.SizeToStr(float(abs(fs_free[dir].free) + 1)) required_list[make_fs_id(dir)] = FreeSpaceRequired(apt_pkg.SizeToStr(fs_free[dir].need), make_fs_id(dir), free_at_least) continue fs_free[dir] if len(required_list) > 0: []([] % [ str(i) for i in required_list ]) raise NotEnoughFreeSpaceError(required_list.values()) len(required_list) > 0 return True if __name__ == '__main__': import DistUpgradeConfigParser import DistUpgradeView print 'foo' c = MyCache(DistUpgradeConfigParser.DistUpgradeConfig('.'), DistUpgradeView.DistUpgradeView(), None) print c.checkFreeSpace() sys.exit() c.clear() c.create_snapshot() c.installedTasks c.installTasks([ 'ubuntu-desktop']) print c.getChanges() c.restore_snapshot()